package com.fingard.dsp.tcpserver;

import java.io.File;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.HashMap;

import com.fingard.FGBiz;
import com.fingard.dsp.DSPSet;
import com.fingard.dsp.bank.directConfig.FileSaveSet;
import com.fingard.dsp.bank.helpers.FileType;
import com.fingard.dsp.bank.reqrespobj.ReqRespHeader;
import com.fingard.dsp.bank.sepro.ReceiptPro;
import com.fingard.text.StringHelper;

public class SocketReceiver {

    public byte[] reqBytes;

    public int contentLength ;
    public int contentStartIndex ;

    public int readedLength;

    public Socket socketClient;
    public String charsetName;

    public String sourceIP;
    public int receiveOffSet;

    public boolean isCipherSocket;
    public String cipherKey;
    public String cipherIV;
    public String digestSign;

    public String action;
    public boolean isSyncFile;
	public boolean isReqSign;
	public boolean isReqEncrypt;
    public String syncCode;
    public String syncMsg;
    public String oriFilePath;
    public String trgFilePath;
    public String fileType;
    public File saveFile;
    public FileOutputStream saveFileStream;

    public int readHeadStartIndex;

    public boolean isCompleted;

    public boolean isNeedCloseConn;

    public boolean hasError;
    public String errMsg;
    public boolean appendFile;

    /**远程租户端连接，保持长连接*/
    public boolean isTenantRemoting;

    /**租户*/
    public String tenant;
    
    public boolean isHttp;
    public String httpMethod;
    public String visitPage;
    
    /**连续读取字节为0的次数*/
    public int readZeroCount;

    public SocketChannel clientSocketChannel;
    public SocketReceiver(SocketChannel p_socketChannel, String p_charsetName) {
    	clientSocketChannel = p_socketChannel;
    	charsetName = p_charsetName;
    	reset();
	}
    public SocketReceiver(Socket p_socket, String p_charsetName) {
    	socketClient = p_socket;
    	charsetName = p_charsetName;
    	reset();
	}

	public SocketReceiver(String p_charsetName) {
		charsetName = p_charsetName;
		reset();
	}
    
    public String getClientIp(){
    	if(clientSocketChannel != null){
    		InetAddress addr = clientSocketChannel.socket().getInetAddress();
    		return addr.getHostAddress();
    	}else if(socketClient != null){
    		InetAddress addr = socketClient.getInetAddress();
    		return addr.getHostAddress();
    	}
    	return "";
    }
    
    /**取得原始请求字符串
     * @throws UnsupportedEncodingException */
    public String getRowReqString(String pCharset) throws UnsupportedEncodingException{
    	return new String(reqBytes, 0, readedLength, pCharset);
    }
    
    /**获取内容字节，即去掉通讯头部*/
    public byte[] getContentBytes(){
    	byte[] retBytes = new byte[contentLength];
    	System.arraycopy(reqBytes, contentStartIndex, retBytes, 0, retBytes.length);
    	return retBytes;
    }
    
    public void reset(){
    	headKV = new HashMap<String, String>();
    	hostRawString="";
    	isHttp = false;
    	httpMethod = "";
    	visitPage = "";
    	readZeroCount = 0;
    	reqBytes = null;
    	isNeedCloseConn = false;
    	contentLength = -1;
    	contentStartIndex = -1;
    	readedLength = 0;
    	receiveOffSet = 0;
    	isSyncFile = false;
    	isCipherSocket = false;
    	readHeadStartIndex=0;
    	isCompleted = false;
    	hasError=false;
    	appendFile=false;
    	errMsg="";
    }
    
    public void openSaveFile(ReqRespHeader tmpHeader) throws Exception{
    	syncCode = "";
    	syncMsg = "";
    	if(StringHelper.isNullOrEmpty(oriFilePath)){
    		return;
    	}
    	if(FileType.dataFile.equalsIgnoreCase(fileType)){
    		trgFilePath = FGBiz.dspCenter.dspSet.dataDirPath + File.separator + StringHelper.trimStartFileSp(oriFilePath);
    	}else if(FileType.bankFile.equalsIgnoreCase(fileType)){
    		trgFilePath = DSPSet.replaceFilePath(oriFilePath);
    	}else if(FileType.receipt.equalsIgnoreCase(fileType)){
    		String mDir = ReceiptPro.getReceiptProConfig().localSaveMainDir;
    		if(StringHelper.isNullOrEmpty(mDir)){
    			/*
    			FileSaveSet fsSet = FGBiz.dspCenter.dspConfig.getFileSaveSet(fileType);
    	    	String mainDir = fsSet.getMainDir(tmpHeader.syBank);
    	    	if(fsSet!=null && StringHelper.hasAnyChar(mainDir)){
    	    		mDir = mainDir;
    	    	}else{
    	    		mDir = FGBiz.DSPHOME_Parent;
    	    	}*/
    			throw new Exception("ReceiptPro.xml未设置回单保存主目录localSaveMainDir");
    		}
    		trgFilePath = StringHelper.trimEndFileSp(mDir) + File.separator + StringHelper.trimStartFileSp(oriFilePath);
    	}else{
	    	String mDir;
	    	
	    	FileSaveSet fsSet = FGBiz.dspCenter.dspConfig.getFileSaveSet(fileType);
	    	String mainDir = fsSet.getMainDir(tmpHeader.syBank);
	    	if(fsSet!=null && StringHelper.hasAnyChar(mainDir)){
	    		mDir = mainDir;
	    	}else{
	    		mDir = FGBiz.DSPHOME_Parent;
	    	}
	
	    	trgFilePath = StringHelper.trimEndFileSp(mDir) + File.separator + StringHelper.trimStartFileSp(oriFilePath);
    	}
    	saveFile = new File(trgFilePath);
    	
		File parentDir = new File(saveFile.getParent());
		if(!parentDir.exists()){
	    	parentDir.mkdirs();
	    }
		//if(!saveFile.exists()){
		//	saveFile.createNewFile();
	    //}
		saveFileStream = new FileOutputStream(saveFile, appendFile);
    }
    private static byte tmpByteLt = '<';//"<".getBytes("gbk")[0];
    private static byte tmpHeadCut1 = '\r';//"\\r".getBytes("gbk")[0];
    private static byte tmpHeadCut2 = '\n';//"\\n".getBytes("gbk")[0];
    public HashMap<String, String> headKV;
    
    public String hostRawString = "";
    public String refererRawString = "";

    public void getHeader(ReqRespHeader tmpHeader) throws UnsupportedEncodingException{
        if (contentLength == -1 || contentStartIndex == -1) {
            for (int i = readHeadStartIndex; i < readedLength; i++) {
            	if (reqBytes[i] == tmpHeadCut2){// 是\n
                    int tmpEndCount = i - readHeadStartIndex;
                    if (i > 1 && reqBytes[i - 1] == tmpHeadCut1){// 前一个字符是\r
                    	tmpEndCount--;
                    }
                    String tmpHeadKeyValue = new String(reqBytes, readHeadStartIndex, tmpEndCount, charsetName);
                    String tmpKey = "";
                    String tmpValue = "";
                    
                    int idx1 = tmpHeadKeyValue.indexOf(":");
                    if(idx1>0){
                    	tmpKey = tmpHeadKeyValue.substring(0,idx1).toLowerCase().trim();
						if(!"filepath".equals(tmpKey)) {
							tmpValue = tmpHeadKeyValue.substring(idx1 + 1).toLowerCase();
						}else{
							tmpValue = tmpHeadKeyValue.substring(idx1 + 1);
						}
                    }else{
                    	tmpKey = tmpHeadKeyValue.toLowerCase().trim();
                    }
                    headKV.put(tmpKey, tmpValue.trim());

                    if (isHttp==false && tmpKey.contains("http") && (tmpKey.startsWith("post") || tmpKey.startsWith("get") || tmpKey.startsWith("head"))) {
                    	isHttp = true;
                    	if(StringHelper.hasAnyChar(FGBiz.dspCenter.dspSet.httpReqDefCharset)){
                    		this.charsetName = FGBiz.dspCenter.dspSet.httpReqDefCharset;
                    	}
                        String[] pValues = tmpKey.split(" ");
                        httpMethod = pValues[0].toLowerCase();
                        if (pValues.length > 1) {
                            visitPage = pValues[1];
                        }
                    }
                    if (tmpKey.equals("host")){
                    	hostRawString = tmpHeadKeyValue;
                    }
                    if (tmpKey.equals("referer")){
                    	refererRawString = tmpHeadKeyValue;
                    }

					if(tmpKey.equals("content-sign")){
						isReqSign = Boolean.valueOf(tmpValue.trim());
					}
					if(tmpKey.equals("content-encrypt")){
						isReqEncrypt = Boolean.valueOf(tmpValue.trim());
					}

                    if (tmpKey.equals("content-length")){
                    	contentLength = Integer.valueOf(tmpValue.trim());
                    }else if (tmpKey.equals("cipher-length")){
                    	isCipherSocket = true;
                    	contentLength = Integer.valueOf(tmpValue.trim());
                    }else if (tmpKey.equals("tenant-connect")){
                    	isTenantRemoting = true;
                    	isCipherSocket = true;
                    	contentLength = Integer.valueOf(tmpValue.trim());
                    }else if (tmpKey.equals("syncfile-length")){
                    	isSyncFile = true;
                    	contentLength = Integer.valueOf(tmpValue.trim());
                    	action = "syncfile";
                    	tmpHeader.transType = "syncfile";
                    }else if (tmpKey.equals("action")){
                    	action = tmpValue;
                    }else if (tmpKey.equals("append")){
                    	if("true".equals(tmpValue)){
                    		appendFile = true;
                    	}
                    }else if (tmpKey.equals("bankcode")){
                    	tmpHeader.bankCode = tmpValue;
                    }else if (tmpKey.equals("sybank")){
                    	tmpHeader.syBank = tmpValue;
                    }else if (tmpKey.equals("filepath")){
                    	oriFilePath = tmpValue.replace("\\", File.separator).replace("/", File.separator);
                    }else if (tmpKey.equals("filetype")){
                    	fileType = tmpValue;
                    }else if (tmpKey.equals("charset")){
                    	charsetName = tmpValue;
                    }else if (tmpKey.equals("cipher-key")){
                    	cipherKey = tmpValue;
                    }else if (tmpKey.equals("cipher-iv")){
                    	cipherIV = tmpValue;
                    }else if (tmpKey.equals("digest-sign")){
                    	digestSign = tmpValue;
                    }
                    readHeadStartIndex = i + 1;
                    if (isHttp || isCipherSocket || isTenantRemoting || isSyncFile || "getfile".equals(action) || "savetodb".equals(action) || "sssmap".equals(action)){//如果是密文或者同步文件，以两个\r\n结束头部
                        if ("sssmap".equals(action)) {
                        	int index = new String(reqBytes, FGBiz.dspCenter.dspSet.charsetName).indexOf("\r\n");
							contentStartIndex = index+2;
						}
                    	if (receiveOffSet > (i + 2)){
                            if (reqBytes[i + 1] == tmpHeadCut1 && reqBytes[i + 2] == tmpHeadCut2){
                            	if("getfile".equals(action) && contentLength<0){
                            		contentLength = 0;//getfile 只有通讯头部，没有内容
                            		contentStartIndex = 0;
                            	}else{
                            		contentStartIndex = i + 3;
                            	}
                            	if("get".equals(httpMethod)){
                                	if(contentLength<0){
                                		contentLength = 0;
                                	}
                                }
                                break;
                            }
                        }
                    }else if (receiveOffSet > (i + 1) && reqBytes[i + 1] == tmpByteLt){
                    	contentStartIndex = i + 1;
                        break;
                    }
                }else if (reqBytes[i] == tmpByteLt){// 是<
                	contentStartIndex = i;
                    break;
                }
            }
        }
    }
}
